package de.tud.binpacking.data;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import de.tud.binpacking.instance.Instance;

public class Batch {

	private Instance instance;
	
	private Set<Order> orders = new HashSet<Order>();
	
	private int freeCapacity;
	
	public Batch(Instance instance) {
		this.instance = instance;
		this.freeCapacity = instance.getCapacity();
	}
	
	public Batch(Instance instance, Order order) {
		this(instance);
		this.freeCapacity = instance.getCapacity();
		add(order);
	}
	
	public Batch(Instance instance, Collection<Order> orders) {
		this(instance);
		for (Order order : orders) {
			add(order);
		}
	}
	
	public Set<Order> getOrders() {
		return this.orders;
	}
	
	public int getFreeCapacity() {
		return freeCapacity;
	}
	
	public boolean add(final Order order) {
		if (freeCapacity >= order.size()) {
			freeCapacity -= order.size();
			return this.orders.add(order);
		}
		return false;
	}
	
	public void remove(final Order order) {
		if (orders.remove(order)) {
			freeCapacity += order.size();
		}
	}
	
	public double getPathLength() {
		
		if (orders.isEmpty()) {
			return 0;
		}
		
		int noAisles = getAisles().size();
		
		if (noAisles == instance.getNoAisles()) {
			return instance.getMaxLength();
		}
		
		int lastAisle = 0;
		int lastPosition = 0;
		
		for (Order order : orders) {
			if (order.getLastAisle() >= lastAisle) {
				lastAisle = order.getLastAisle();
				
				int newLastPosition = order.getItems().get(order.getItems().size() - 1).getCell();
				
				if (newLastPosition > lastPosition) {
					lastPosition = newLastPosition;
				}
			}
		}
		
		if ((noAisles & 1) == 0) {
			return 		noAisles * instance.getAisleLength()
					+ 	2 * lastAisle * instance.getDistBetweenAisles()
					+ 	2 * instance.getDistDepotAisle();
		} else {
			return 		(noAisles - 1) * instance.getAisleLength()
					+	2 * (lastPosition * instance.getCellLength() + instance.getDistToFirstItem())
					+ 	2 * lastAisle * instance.getDistBetweenAisles()
					+	2 * instance.getDistDepotAisle();
		}
		
	}
	
	public Set<Integer> getAisles() {
		Set<Integer> aisles = new HashSet<Integer>();
		
		for(Order curOrder : orders){
			aisles.addAll(curOrder.getAisles());
		}
		
		return aisles;
	}
	
	@Override
	public String toString() {
		String orders = "";
		for(Order order : this.orders){
			orders += order + " ";
		}
		return "Batch: {" + orders + "}" ;
	}

	public Batch copy() {
		Batch newBatch = new Batch(this.instance);
		newBatch.orders.addAll(this.orders);
		newBatch.freeCapacity = this.freeCapacity;
		return newBatch;
	}
	
	public boolean check(Order toRemove, Order toAdd) {
		return (freeCapacity+toRemove.size()-toAdd.size() >= 0);
	}

}

